﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using Newtonsoft.Json;
using System.Windows.Data;
using System.Web.UI.WebControls;
using System.Windows.Controls;
using System.Collections.ObjectModel;
using System.Windows;

using Res = WasaWasa.Properties.Resources;
using System.Threading;

namespace WasaWasa
{
    partial class MainWindow
    {
        private const string ApiPathChannelList = "/channel_user/user_list.json";
        private const string ApiPathChannelTimelime = "/channel_message/list.json";

        private ObservableCollection<TimelineBundle> timelines;

        partial void InitializeTimelineTab()
        {
            timelines = new ObservableCollection<TimelineBundle>();
            timelines.Add(new TimelineBundle() { Type = TimelineType.Friends, Name = Res.StringFriends, ApiPath = "/statuses/friends_timeline.json" });
            timelines.Add(new TimelineBundle() { Type = TimelineType.Recent, Name = Res.StringRecent, ApiPath = "/statuses/user_timeline.json" });
            timelines.Add(new TimelineBundle() { Type = TimelineType.Reply, Name = Res.StringReply, ApiPath = "/statuses/replies.json" });
            timelines.Add(new TimelineBundle() { Type = TimelineType.Public, Name = Res.StringPublic, ApiPath = "/statuses/public_timeline.json" });
            timelines.Add(new TimelineBundle() { Type = TimelineType.SL, Name = Res.StringSecondLife, ApiPath = "/statuses/sl_timeline.json" });
#if DEBUG
#else
            LoadChannelList();
#endif
            tabsTimeline.ItemsSource = timelines;
            tabsTimeline.SelectedIndex = 0;
        }

        /// <summary>
        /// タイムラインを読み込んで表示します。
        /// </summary>
        private void LoadTimeline(TimelineBundle tlb)
        {
            AppendLogText(tlb.Name + Res.MessageLoadingTimeline);
            tlb.IsLoaded = true;

            UriBuilder ub = new UriBuilder(Uri.UriSchemeHttp, ApiHost, ApiPort, tlb.ApiPath, tlb.ApiParam);

            HttpWebRequest wreq = WebRequest.Create(ub.Uri) as HttpWebRequest;
            wreq.Method = WebRequestMethods.Http.Get;
            if (!SetWebRequestOptions(wreq)) return;
            wreq.Timeout = 60000;//TODO:タイムアウト時間を設定可能にする
            wreq.IfModifiedSince = tlb.lastModified;
            IAsyncResult oar = wreq.BeginGetResponse(new AsyncCallback(delegate(IAsyncResult ar)
            {
                try
                {
                    using (HttpWebResponse wres = wreq.EndGetResponse(ar) as HttpWebResponse)
                    {
                        AppendLogText(tlb.Name + Res.OperationLoadTimeline + Enum.GetName(typeof(HttpStatusCode), wres.StatusCode));

                        if (wres.StatusCode == HttpStatusCode.OK)
                        {
                            tlb.lastModified = wres.LastModified;

                            using (Stream sres = wres.GetResponseStream())
                            using (StreamReader srres = new StreamReader(sres))
                            using (JsonTextReader jtr = new JsonTextReader(srres))
                            {
                                List<StatusClass> ttl = null;
                                try
                                {
                                    ttl = new JsonSerializer().Deserialize(jtr, typeof(List<StatusClass>)) as List<StatusClass>;
                                }
                                catch (JsonReaderException)
                                {
                                    AppendLogText(tlb.Name + Res.OfTimeline + Res.ErrorFailedReadingJson);
                                    return;
                                }
                                catch (JsonSerializationException ex)
                                {
                                    AppendLogText(tlb.Name + Res.OfTimeline + Res.ErrorFailedSerializingJson);
                                    Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
                                    {
                                        ExceptionWindow.Show(ex);
                                    }));
                                }
                                ObservableCollection<StatusClass> gtl = tlb.Timeline;
                                long lastid = gtl.Count > 0 ? gtl[0].Id : 0;
                                int capacity = new Func<int>(() =>
                                {
                                    switch (tlb.Type)
                                    {
                                        case TimelineType.Friends:
                                            return def.FriendsTimelineCapacity;
                                        case TimelineType.Recent:
                                            return def.RecentTimelineCapacity;
                                        case TimelineType.Public:
                                            return def.PublicTimelineCapacity;
                                        case TimelineType.SL:
                                            return def.SLTimelineCapacity;
                                        case TimelineType.Channel:
                                            return def.ChannelTimelineCapacity;
                                        case TimelineType.User:
                                            return def.UserTimelineCapacity;
                                        default:
                                            return 20;
                                    }
                                })();
                                ttl.Reverse();

                                Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
                                {
                                    if (tlb.Type == TimelineType.Channel)
                                    {
                                        gtl.Clear();
                                        foreach (var tl in ttl)
                                        {
                                            gtl.Insert(0, tl);
                                        }
                                        tlb.LastLoadedCount = gtl.Count;
                                    }
                                    else
                                    {
                                        int cnt = 0;
                                        foreach (var tl in ttl)
                                        {
                                            if (lastid < tl.Id)
                                                gtl.Insert(0, tl);
                                            cnt++;
                                        }
                                        while (gtl.Count > capacity)
                                        {
                                            gtl.RemoveAt(capacity);
                                        }
                                        tlb.LastLoadedCount = cnt;
                                    }
                                }));

                                tlb.LastLoaded = DateTime.Now;
                            }
                        }
                    }
                }
                catch (WebException ex)
                {
                    AppendLogText(tlb.Name + Res.OperationLoadTimeline + Enum.GetName(typeof(HttpStatusCode), (ex.Response as HttpWebResponse).StatusCode));
                }
            }), null);
            ThreadPool.RegisterWaitForSingleObject(oar.AsyncWaitHandle, new WaitOrTimerCallback(TimeOutCallback), new object[] { wreq, tlb.Name + Res.OperationLoadTimeline }, 30000, true);
        }

        private void LoadChannelList()
        {
            AppendLogText(Res.MessageLoadingChannelList);

            int i = 0;
            while (i < timelines.Count)
            {
                if (timelines[i].Type == TimelineType.Channel)
                    timelines.RemoveAt(i);
                else
                    i++;
            }

            UriBuilder ub = new UriBuilder(Uri.UriSchemeHttp, ApiHost, ApiPort, ApiPathChannelList, string.Format("?login_id={0}", def.UserName));

            HttpWebRequest wreq = WebRequest.Create(ub.Uri) as HttpWebRequest;
            wreq.Method = WebRequestMethods.Http.Get;
            if (!SetWebRequestOptions(wreq)) return;
            IAsyncResult oar = wreq.BeginGetResponse(new AsyncCallback(delegate(IAsyncResult ar)
            {
                try
                {
                    using (HttpWebResponse wres = wreq.EndGetResponse(ar) as HttpWebResponse)
                    {
                        AppendLogText(Res.OperationLoadChannelList + Enum.GetName(typeof(HttpStatusCode), wres.StatusCode));

                        if (wres.StatusCode == HttpStatusCode.OK)
                        {
                            using (Stream sres = wres.GetResponseStream())
                            using (StreamReader srres = new StreamReader(sres))
                            using (JsonTextReader jtr = new JsonTextReader(srres))
                            {
                                ChannelClass tcl = null;
                                try
                                {
                                    tcl = new JsonSerializer().Deserialize(jtr, typeof(ChannelClass)) as ChannelClass;
                                }
                                catch (JsonReaderException)
                                {
                                    AppendLogText(Res.OfChannelList + Res.ErrorFailedReadingJson);
                                    return;
                                }
                                catch (JsonSerializationException ex)
                                {
                                    AppendLogText(Res.OfChannelList + Res.ErrorFailedSerializingJson);
                                    Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(() =>
                                    {
                                        ExceptionWindow.Show(ex);
                                    }));
                                }

                                Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
                                {
                                    foreach (var ch in tcl.Channels)
                                    {
                                        TimelineBundle tlb = new TimelineBundle()
                                        {
                                            Type = TimelineType.Channel,
                                            Name = "#" + ch.Title,
                                            ApiPath = ApiPathChannelTimelime,
                                            ApiParam = "?name_en=" + ch.NameEn,
                                        };
                                        tlb.Tags.Add("Title", ch.Title);
                                        tlb.Tags.Add("NameEn", ch.NameEn);
                                        timelines.Add(tlb);
                                    }
                                }));
                            }
                        }
                    }
                }
                catch (WebException ex)
                {
                    AppendLogText(Res.OperationLoadChannelList + Enum.GetName(typeof(HttpStatusCode), (ex.Response as HttpWebResponse).StatusCode));
                }
            }), null);
            ThreadPool.RegisterWaitForSingleObject(oar.AsyncWaitHandle, new WaitOrTimerCallback(TimeOutCallback), new object[] { wreq, Res.OperationLoadChannelList }, 30000, true);
        }
    }
}
